package com.iking.toolkit.util;

import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.core.codec.Base64Encoder;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.iking.toolkit.model.UserTokenRes;
import com.iking.toolkit.model.WebToken;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.xml.bind.DatatypeConverter;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor;
import net.sf.json.util.JavaIdentifierTransformer;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 工具类
 *
 * @author hufx
 * @version 1.0
 * @date 2017年1月22日下午8:02:18
 */
@Component
public class SysUtil {
    @SuppressWarnings("unused")
    private static final int defaultLogTime = 7;// 设置默认日志缓存时间为7天
    //ftp服务器ip地址
    private static String FTP_ADDRESS;
    //端口号
    private static int FTP_PORT;
    //用户名
    private static String FTP_USERNAME;
    //密码
    private static String FTP_PASSWORD;
    private static SysUtil sysUtil = new SysUtil();
    private static Logger log = LoggerFactory.getLogger(SysUtil.class);
    private static WebToken webToken = new WebToken();

    static {
        try {
            Resource resource = new ClassPathResource("/webtoken.properties");
            Properties Props = PropertiesLoaderUtils.loadProperties(resource);
            webToken.setExpiresSecond(Props.getProperty("expiresSecond") == null
                    ? 6379
                    : Integer.parseInt(Props.getProperty("expiresSecond")));
            webToken.setName(Props.getProperty("name"));
            webToken.setSalt(Props.getProperty("salt"));
        } catch (IOException e) {
            log.error("获取 WebTokenProps : " + e);
        }

    }

    /**
     * 功能描述:集合对象去重
     *
     * @param: [keyExtractor]
     * @author: yfl
     * @date: 2023/8/29 14:06
     */
    public  static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

    /**
     * 发送http POST请求
     *
     * @return
     * @throws ClientProtocolException
     * @throws IOException             String
     * @author hufx
     * @date 2017年5月16日上午10:46:55
     */
    @SuppressWarnings({"resource"})
    public static String doPOSTByJSONString(String url, String params)
            throws ClientProtocolException, IOException {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        if (StringUtils.isBlank(params)) {
            return null;
        }
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        log.info("_thisparams = " + params);
        StringEntity entity = new
                StringEntity(params, "utf-8");//解决中文乱码问题
        entity.setContentEncoding("UTF-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        HttpResponse httpResponse = httpClient.execute(httpPost);
        if (httpResponse != null) {
            HttpEntity httpEntity = httpResponse.getEntity();
            String response = EntityUtils.toString(httpEntity);
            return response;
        }
        return null;
    }

    /**
     * 获取指定日期是星期几<br>
     *
     * @param date
     * @return 指定日期是星期几
     */
    public static String getWeekOfDate(Date date) {
        String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (w < 0) {
            w = 0;
        }
        return weekDays[w];
    }

    /**
     * 功能描述: 获取判断类型字符串:1.大于 2.小于 3.等于
     *
     * @param: [judgeType]
     * @return: java.lang.String
     * @auther: yfl
     * @date: 2022/1/20 0020 18:58
     */
    public static String getJudgeType(Integer judgeType) {
        String str = "";
        switch (judgeType) {
            case 1:
                str = ">";
                break;
            case 2:
                str = "<";
                break;
            case 3:
                str = "=";
                break;
        }
        return str;
    }

    /**
     * 功能描述: 版本号符合规则验证
     *
     * @param: str:版本号
     * @return:
     * @auther: yfl
     * @date: 2018/10/10 15:57
     */
    public static Boolean checkVersion(String str) {
        String version = "\\d+(.\\d+)*";
        Pattern pattern = Pattern.compile(version);
        // 忽略大小写的写法
        // Pattern pat = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str);
        // 字符串是否与正则表达式相匹配
        return matcher.matches();
    }

    /**
     * 比较版本号的大小,前者大则返回一个正数,后者大返回一个负数,相等则返回0 规则是按日期订的例如：2.10.15 项目启动第2年的8月15号
     *
     * @param version1
     * @param version2
     * @return
     */
    public static Integer compareVersion(String version1, String version2) {
        int diff = 0;
        try {
            if (version1 == null || version2 == null) {
                throw new Exception("compareVersion error:illegal params.");
            }
            String[] versionArray1 = version1.split("\\.");// 注意此处为正则匹配，不能用"."；
            for (int i = 0; i < versionArray1.length; i++) { // 如果位数只有一位则自动补零（防止出现一个是04，一个是5 直接以长度比较）
                if (versionArray1[i].length() == 1) {
                    versionArray1[i] = "0" + versionArray1[i];
                }
            }
            String[] versionArray2 = version2.split("\\.");
            for (int i = 0; i < versionArray2.length; i++) {// 如果位数只有一位则自动补零
                if (versionArray2[i].length() == 1) {
                    versionArray2[i] = "0" + versionArray2[i];
                }
            }
            int idx = 0;
            int minLength = Math.min(versionArray1.length, versionArray2.length);// 取最小长度值

            while (idx < minLength && (diff = versionArray1[idx].length() - versionArray2[idx].length()) == 0// 先比较长度
                    && (diff = versionArray1[idx].compareTo(versionArray2[idx])) == 0) {// 再比较字符
                ++idx;
            }
            // 如果已经分出大小，则直接返回，如果未分出大小，则再比较位数，有子版本的为大；
            diff = (diff != 0) ? diff : versionArray1.length - versionArray2.length;
        } catch (Exception e) {
            return null;
        }
        return diff;
    }

    /**
     * 获取自定义随机数
     */
    public static String getRandom(Integer num) {
        int[] ints = NumberUtil.generateRandomNumber(0, 9, num);
        String str = ArrayUtil.join(ints, "");
        return str;
    }

    /**
     * 获取6位随机数
     */
    public static String getRandom() {
        int[] ints = NumberUtil.generateRandomNumber(0, 9, 6);
        String str = ArrayUtil.join(ints, "");
        return str;
    }

    /**
     * 获取8位随机数
     */
    public static String getRandomNumber() {
        int[] ints = NumberUtil.generateRandomNumber(0, 9, 8);
        String str = ArrayUtil.join(ints, "");
        return str;
    }

    /**
     * 根据开始时间和结束时间返回时间段内的时间集合
     *
     * @param beginDate
     * @param endDate
     * @return
     * @Title: getDatesBetweenTwoDate
     * @author yfl
     * @date 2018年3月15日 下午5:17:12
     */
    public static List<Date> getDatesBetweenTwoDate(Date beginDate, Date endDate) {

        List<Date> lDate = new ArrayList<Date>();
        lDate.add(beginDate);// 把开始时间加入集合
        Calendar cal = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        cal.setTime(beginDate);
        boolean bContinue = true;
        while (bContinue) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            cal.add(Calendar.DAY_OF_MONTH, 1);

            if (isSameDate(cal.getTime(), endDate)) {
                break;
            }
            // 测试此日期是否在指定日期之后
            if (endDate.after(cal.getTime())) {
                lDate.add(cal.getTime());
            } else {
                break;
            }
        }
        if (!isSameDate(beginDate, endDate)) {
            lDate.add(endDate);// 把结束时间加入集合
        }

        return lDate;
    }

    /**
     * 判断日期是否是同一天
     *
     * @param date1
     * @param date2
     * @return boolean
     * @throws @Title: isSameDate
     * @author yfl
     * @date 2018年3月29日 上午9:32:16
     */
    public static boolean isSameDate(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);

        boolean isSameYear = cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
        boolean isSameMonth = isSameYear && cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH);
        boolean isSameDate = isSameMonth && cal1.get(Calendar.DAY_OF_MONTH) == cal2.get(Calendar.DAY_OF_MONTH);

        return isSameDate;
    }

    /***
     * @desc MD5加密
     * @param inStr
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String getMD5(String inStr) throws NoSuchAlgorithmException {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        char[] charArray = inStr.toCharArray();
        byte[] byteArray = new byte[charArray.length];
        for (int i = 0; i < charArray.length; i++) {
            byteArray[i] = (byte) charArray[i];
        }
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }

    /**
     * 生成UUID
     *
     * @return
     * @author yfl
     * @date 2017年3月24日 下午6:17:49
     */
    public static String getUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 日期格式化
     *
     * @return
     * @author yfl
     * @date 2017年6月2日 下午4:57:12
     */
    public static String DateFormat(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String tim = sdf.format(date);
        return tim;
    }

    /**
     * 日期比较 1:date1 > date2 -1:date1<date2 0:date1 = date2
     *
     * @param DATE1
     * @param DATE2
     * @return
     * @throws ParseException
     * @author yfl
     * @date 2017年6月12日 下午4:47:32
     */
    public static int compare_date(String DATE1, String DATE2) throws ParseException {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date dt1 = df.parse(DATE1);
        Date dt2 = df.parse(DATE2);
        if (dt1.getTime() > dt2.getTime()) {
            return 1;
        } else if (dt1.getTime() < dt2.getTime()) {
            return -1;
        }
        return 0;
    }

    /**
     * 功能描述: 检查手机号正确性
     *
     * @param: [phone]
     * @return: boolean
     * @author: yfl
     * @date: 2022/4/12 12:22
     */
    public static boolean inspectionPhone(String phone) {
        Pattern pattern = Pattern.compile("^[1][0-9][0-9]{9}$"); // 验证手机号
        Matcher matcher = pattern.matcher(phone);
        return matcher.matches();

    }

    /**
     * 功能描述: 检查固定电话正确性
     *
     * @param: [fixedPhone]
     * @return: boolean
     * @author: yunh
     * @date: 2022/6/24 9:41
     **/
    public static boolean inspectionFixedPhone(String fixedPhone) {
        Pattern pattern = Pattern.compile("^0\\d{2,3}[-]?\\d{7,8}|0\\d{2,3}\\s?\\d{7,8}$"); //验证固定电话
        Matcher matcher = pattern.matcher(fixedPhone);
        return matcher.matches();
    }

    /**
     * @Description: 获取当前登录的用户id
     * @Param: [request]
     * @Author: wk
     * @Date: 7/2/2020 上午11:26
     */
    public static UserTokenRes getUserByWebToken(HttpServletRequest request) {
        try {
            String jsonWebToken = request.getHeader("token");
            if (jsonWebToken == null) {
                return null;
            }
            Map<String, Object> tUserMap = (Map<String, Object>) parseWebToken(jsonWebToken);
            if (tUserMap == null) {
                return null;
            }
            UserTokenRes userTokenRes = new UserTokenRes();
            String userId = (String) tUserMap.get("userId");
            String userName = (String) tUserMap.get("userName");
            userTokenRes.setUserId(userId);
            userTokenRes.setUserName(userName);
            return userTokenRes;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 功能描述: 根据自定义key生成token
     *
     * @param: [key, obj]
     * @return: java.lang.String
     * @author: yfl
     * @date: 2022/4/28 12:25
     */
    public static String getWebTokenByKey(String key, Object obj) {

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        // 生成签名密钥
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(webToken.getSalt());
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName());
        // 添加构成JWT的参数
        JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT").claim(key, obj).setIssuer(webToken.getName())
                .signWith(SignatureAlgorithm.HS256, signingKey);
        // 添加Token过期时间
        long TTLMillis = webToken.getExpiresSecond() * 24 * 60 * 60 * 1000;
        if (TTLMillis >= 0) {
            long expMillis = nowMillis + TTLMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp).setNotBefore(now);
        }
        // 生成JWT
        return builder.compact();
    }

    /**
     * 功能描述: 根据自定义key生成指定时间有效期token
     *
     * @param: [key, obj,minutes]
     * @return: java.lang.String
     * @author: yfl
     * @date: 2022/4/28 12:25
     */
    public static String getWebTokenByKeyAndTime(String key, Object obj, Integer minutes) {

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        // 生成签名密钥
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(webToken.getSalt());
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName());
        // 添加构成JWT的参数
        JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT").claim(key, obj).setIssuer(webToken.getName())
                .signWith(SignatureAlgorithm.HS256, signingKey);
        // 添加Token过期时间
        long TTLMillis = minutes * 60 * 1000;
        if (TTLMillis >= 0) {
            long expMillis = nowMillis + TTLMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp).setNotBefore(now);
        }
        // 生成JWT
        return builder.compact();
    }

    /**
     * 功能描述: 生成用户登录token
     *
     * @param: [key, obj]
     * @return: java.lang.String
     * @author: yfl
     * @date: 2022/4/28 12:25
     */
    public static String getWebToken(Object obj) {
        return getWebTokenByKey("user_id", obj);
    }

    /**
     * 生成用户登录token(不带过期时间)
     *
     * @param obj
     * @return
     */
    public static String getWebTokenNoTime(Object obj) {
        return getWebTokenByKeyNoTime("user_id", obj);
    }

    /**
     * 功能描述: 根据自定义key生成token(不带过期时间)
     *
     * @param: [key, obj]
     * @return: java.lang.String
     * @author: yfl
     * @date: 2022/4/28 12:25
     */
    public static String getWebTokenByKeyNoTime(String key, Object obj) {

        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        // 生成签名密钥
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(webToken.getSalt());
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName());
        // 添加构成JWT的参数
        JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT").claim(key, obj).setIssuer(webToken.getName())
                .signWith(SignatureAlgorithm.HS256, signingKey);
        // 生成JWT
        return builder.compact();
    }

    /**
     * 功能描述: 解析用户登录token
     *
     * @param: [jsonWebToken, key]
     * @author: yfl
     * @date: 2022/4/28 12:27
     */
    public static Map<String, Object> parseWebToken(String jsonWebToken) {
        return parseWebTokenBykey(jsonWebToken, "user_id");
    }

    /**
     * 功能描述: 根据key解析token
     *
     * @param: [jsonWebToken, key]
     * @author: yfl
     * @date: 2022/4/28 12:28
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> parseWebTokenBykey(String jsonWebToken, String key) {

        try {
            Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(webToken.getSalt()))
                    .parseClaimsJws(jsonWebToken).getBody();

            Map<String, Object> res = (Map<String, Object>) claims.get(key);
            return res;
        } catch (Exception ex) {
            log.error("解析token值：" + ex);
        }
        return null;
    }

    /**
     * 功能描述: 获取token保存时长
     *
     * @param: []
     * @return: long
     * @author: yfl
     * @date: 2022/4/13 16:14
     */
    public static long getWebTokenSaveTime() {
        return webToken.getExpiresSecond() * 24 * 60 * 60 * 1000;
    }

    /**
     * 获取webtoken的失效时间
     *
     * @param jsonWebToken
     * @param key
     * @return
     * @author yfl
     * @date 2017年7月10日 上午11:52:52
     */
    public static Long getWebTokenTime(String jsonWebToken, String key) {
        try {
            Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(webToken.getSalt()))
                    .parseClaimsJws(jsonWebToken).getBody();
            return claims.getExpiration().getTime();
        } catch (Exception ex) {
            log.error("解析token值：" + ex);
        }
        return null;
    }


    /**
     * base64编码
     *
     * @param bstr
     * @return String
     * @author hufx
     * @date 2017年5月19日下午5:44:58
     */
    @SuppressWarnings("restriction")
    public static String getBase64(byte[] bstr) {
        return new Base64Encoder().encode(bstr);
    }

    /**
     * base64解码
     *
     * @param str
     * @return
     * @throws IOException byte[]
     * @author hufx
     * @date 2017年5月19日下午5:45:08
     */
    @SuppressWarnings("restriction")
    public static byte[] parseBase64(String str) throws IOException {
        byte[] bt = null;
        Base64Decoder decoder = new Base64Decoder();
        bt = decoder.decode(str);
        return bt;
    }

    /**
     * java对象转json对象 <br/>
     * 此方法返回数据中的日期将全部以日期字符串表示 再次使用时使用Date即可接收 <br/>
     * 此类将处理以下问题：<br/>
     * 将java对象使用JSONObject.fromObject(Object)进行转换并且使用JSONObject.toString()返回字符串时,<br/>
     * 会默认将java.util.Date日期转换成下列结果： <br/>
     * "birthday": { "date": 3, "day": 4, "hours": 9, "minutes": 5, "month": 11,
     * "seconds": 1, "time": 1449104701018, "timezoneOffset": -480, "year": 115 },
     * <br/>
     * 为了方便JSON数据的直接使用，因此需要进行配置转换。返回结果如下： <br/>
     * Sat Feb 10 15:42:49 CST 2018
     *
     * @param obj 要转换的对象
     * @return String
     * @author hufx
     * @date 2018年2月10日下午3:31:01
     */
    public static String getJSONAndFormatJSONDate(Object obj) {
        if (obj == null)
            return null;
        JsonConfig jsonConfig = new JsonConfig();
        JsonDateValueProcessor jsonValueProcessor = new JsonDateValueProcessor();
        jsonConfig.registerJsonValueProcessor(Date.class, jsonValueProcessor);
        return JSONObject.fromObject(obj, jsonConfig).toString();
    }

    /**
     * 发送http GET请求
     *
     * @param url
     * @return
     * @throws ClientProtocolException
     * @throws IOException             String
     * @author hufx
     * @date 2017年5月16日下午1:35:57
     */
    @SuppressWarnings({"resource"})
    public static String doGET(String url) throws ClientProtocolException,
            IOException {
        HttpClient httpClient = new DefaultHttpClient();
        //请求超时
        httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 3000);
        //读取超时
        httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 3000);
        HttpGet HttpGet = new HttpGet(url);
        HttpResponse httpResponse = httpClient.execute(HttpGet);
        if (httpResponse != null) {
            HttpEntity httpEntity = httpResponse.getEntity();
            String response = EntityUtils.toString(httpEntity);
            return response;
        }
        return null;
    }

    /**
     * 带参数的post请求
     *
     * @param url
     * @param param
     * @return String
     */
    public static String doPost(String url, Map<String, String> param) {
        // 创建Httpclient对象
        HttpClient httpClient = new DefaultHttpClient();
        HttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建参数列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            log.error("带参数的post请求 失败", e);
        }
        return resultString;
    }

    /**
     * 发送http POST请求
     *
     * @return
     * @throws ClientProtocolException
     * @throws IOException             String
     * @author hufx
     * @date 2017年5月16日上午10:46:55
     */
    @SuppressWarnings({"resource"})
    public static String doPOSTByJSONObject(String url, JSONObject params)
            throws ClientProtocolException, IOException {
        if (StringUtils.isBlank(url)) {
            return null;
        }
        if (params == null || params.size() < 1) {
            return null;
        }
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        log.info("_thisparams = " + params);
        StringEntity entity = new
                StringEntity(params.toString(), "utf-8");//解决中文乱码问题
        entity.setContentEncoding("UTF-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        HttpResponse httpResponse = httpClient.execute(httpPost);
        if (httpResponse != null) {
            HttpEntity httpEntity = httpResponse.getEntity();
            String response = EntityUtils.toString(httpEntity);
            return response;
        }
        return null;
    }

    /**
     * java对象转json对象 <br/>
     * 此方法返回数据中的日期将全部以格式化后的字符串表示 再次使用时需使用String接收 <br/>
     * 格式化规则为pattern确定 <br/>
     * 此类将处理以下问题：<br/>
     * 将java对象使用JSONObject.fromObject(Object)进行转换并且使用JSONObject.toString()返回字符串时,<br/>
     * 会默认将java.util.Date日期转换成下列结果： <br/>
     * "birthday": { "date": 3, "day": 4, "hours": 9, "minutes": 5, "month": 11,
     * "seconds": 1, "time": 1449104701018, "timezoneOffset": -480, "year": 115 },
     * <br/>
     * 为了方便JSON数据的直接使用，因此需要进行配置转换。返回结果如下： <br/>
     * 例如 格式化规则为：yyyy-MM-dd 则结果为 ：2018-02-10
     *
     * @param obj     要转换的对象
     * @param pattern 日期格式化规则
     * @return String
     * @author hufx
     * @date 2018年2月10日下午3:44:17
     */
    public static String getJSONAndFormatJSONDate(Object obj, String pattern) {
        if (obj == null)
            return null;
        JsonConfig jsonConfig = new JsonConfig();
        JsonDateValueProcessor jsonValueProcessor = new JsonDateValueProcessor(pattern);
        jsonConfig.registerJsonValueProcessor(Date.class, jsonValueProcessor);
        return JSONObject.fromObject(obj, jsonConfig).toString();
    }

    /**
     * JOSN对象转java对象忽略大小写 通过JSONObject.toBean() 或 JSONArray.to...()
     *
     * @return JsonConfig
     * @author hufx
     * @date 2017年5月19日下午12:40:44
     */
    public static <T> JsonConfig getJSONCastUpperAndLowerCase(final Class<T> clazz) {
        JsonConfig config = new JsonConfig();
        config.setJavaIdentifierTransformer(new JavaIdentifierTransformer() {
            @Override
            public String transformToJavaIdentifier(String attributeName) {
                Field fields[] = clazz.getDeclaredFields(); // 拿到所有的属性
                if (fields.length < 1) {
                    return attributeName;
                }
                for (int i = 0; i < fields.length; i++) { // 遍历对象的所有属性
                    String typename = fields[i].getGenericType().toString(); // 获取属性类型
                    if (StringUtils.isNotBlank(typename) && typename.length() > 0 && typename.startsWith("class")) {
                        typename = typename.substring(6); // 非基本类型的名称都会以class开头
                        // eg. class
                        // java.lang.String
                    }
                    if (isJavaInnerType(typename)) { // 当属性类型为自定义对象或数组时
                        String _attributeName = fields[i].getName(); // 拿到对象中的属性名称
                        String _attributeNameLower = _attributeName.toLowerCase().trim();// 拿到对象中属性名称的小写
                        String attributeNameLower = attributeName.toLowerCase().trim();// 拿到JSON中的属性名称小写
                        if (_attributeNameLower.equals(attributeNameLower)) { // 当对象中的属性名称与JSON中的属性名称相同时
                            attributeName = _attributeName; // 将JSON中的属性名称换成对象中的属性名称
                        }
                    } else { // 当属性类型不是自定义对象或数组时 替换首字母为小写
                        char[] chars = attributeName.toCharArray();
                        chars[0] = Character.toLowerCase(chars[0]);
                        attributeName = new String(chars);
                    }
                }
                return attributeName;
            }
        });
        config.setRootClass(clazz);
        return config;
    }

    /**
     * 判断对象的属性类型是否是自定义对象或数组/集合
     *
     * @param type Field.getGenericType().getTypeName()获取的反射类型字符串
     * @return boolean 是 返回true 不是则返回false
     * @author hufx
     * @date 2017年5月19日下午4:48:44
     */
    public static boolean isJavaInnerType(String type) {
        List<String> typeList = new ArrayList<String>();
        typeList.add("byte");
        typeList.add("short");
        typeList.add("int");
        typeList.add("long");
        typeList.add("float");
        typeList.add("double");
        typeList.add("boolean");
        typeList.add("char");
        typeList.add("java.lang.Integer");
        typeList.add("java.lang.String");
        typeList.add("java.lang.Short");
        typeList.add("java.lang.Byte");
        typeList.add("java.lang.Character");
        typeList.add("java.lang.Double");
        typeList.add("java.lang.Float");
        typeList.add("java.lang.Boolean");
        typeList.add("java.math.BigInteger");
        typeList.add("java.math.BigDecmail");
        typeList.add("java.util.Date");
        typeList.add("java.sql.Date");
        typeList.add("java.lang.Object");
        typeList.add("java.lang.Number");
        for (String string : typeList) {
            if (!string.equals(type.trim())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 数字转汉字
     *
     * @param param
     * @return
     * @author zhaolei
     * @time 2017年11月23日下午5:59:36
     */
    public static String numberToChinese(int param) {
        String[] s1 = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"};
        String[] s2 = {"十", "百", "千", "万", "十", "百", "千", "亿", "十", "百", "千"};

        String result = "";
        String str = String.valueOf(param);
        int n = str.length();
        for (int i = 0; i < n; i++) {

            int num = str.charAt(i) - '0';

            if (i != n - 1 && num != 0) {
                result += s1[num] + s2[n - 2 - i];
            } else {
                result += s1[num];
            }
        }
        return result;

    }


    /**
     * 计算给定两个日期相差小时数
     *
     * @return
     * @author zhaolei
     * @time 2018年1月22日下午2:07:39
     */
    public static Double getHours(Date beginTime, Date endTime) {
        Double hours = null;
        if (beginTime == null || endTime == null) {
            return null;
        }
        try {
            Long time = (endTime.getTime() - beginTime.getTime()) / (1000 * 60 * 60);
            BigDecimal bg = BigDecimal.valueOf(time.doubleValue());
            hours = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        } catch (Exception e) {
            return null;
        }
        return hours;
    }

    /**
     * 复制单个文件
     * <p>
     * <br/>
     * 参数为文件全路径包含文件全名
     *
     * @param from String 原文件路径 如：c:/fqf.txt
     * @param to   String 复制后路径 如：f:/fqf.txt
     * @return boolean
     */
    @SuppressWarnings("unused")
    public static boolean fileCopy(String from, String to) {


        if (from == null || to == null)
            return false;
        int bytesum = 0;
        int byteread = 0;
        File oldfile = new File(from);
        if (oldfile.exists()) { // 文件存在时
            try (InputStream inStream = new FileInputStream(oldfile)) { // 读入原文件
                File file = new File(to);
                File fileParent = file.getParentFile();
                if (!fileParent.exists()) {
                    fileParent.mkdirs();
                }
                if (!file.createNewFile()) {
                    return false;
                }
                try (FileOutputStream fs = new FileOutputStream(file)) {
                    byte[] buffer = new byte[1024];
                    int length;
                    while ((byteread = inStream.read(buffer)) != -1) {
                        bytesum += byteread; // 字节数 文件大小
                        fs.write(buffer, 0, byteread);
                    }
                    inStream.close();
                }
                return true;
            } catch (IOException e) {
                return false;
            }
        } else {
            return false;
        }


    }

    /**
     * 复制单个文件 <br/>
     * 参数为文件全路径包含文件全名
     *
     * @param from String 原文件路径 如：c:/fqf.txt
     * @param to   String 复制后路径 如：f:/fqf.txt
     * @return boolean
     */
    @SuppressWarnings("unused")
    public static boolean fileCopy(File from, File to) throws IOException {

        if (from == null || to == null)
            return false;
        int bytesum = 0;
        int byteread = 0;
        File oldfile = from;
        if (oldfile.exists()) { // 文件存在时
            try (InputStream inStream = new FileInputStream(oldfile)) { // 读入原文件
                File file = to;
                File fileParent = file.getParentFile();
                if (!fileParent.exists()) {
                    fileParent.mkdirs();
                }
                if (!file.createNewFile()) {
                    return false;
                }
                try (FileOutputStream fs = new FileOutputStream(file)) {
                    byte[] buffer = new byte[1024];
                    int length;
                    while ((byteread = inStream.read(buffer)) != -1) {
                        bytesum += byteread; // 字节数 文件大小
                        fs.write(buffer, 0, byteread);
                    }
                }
                return true;
            } catch (IOException e) {
                return false;
            }
        } else {
            return false;
        }

    }

    /**
     * 向输出流中写文件， 即 读取指定文件并写入到流向的路径
     *
     * @param file 文件
     * @param out  输出流
     * @return boolean
     * @author hufx
     * @date 2018年2月9日下午2:48:08
     */
    @SuppressWarnings("unused")
    public static boolean fileOut(File file, OutputStream out) {

        if (file == null || out == null)
            return false;
        int bytesum = 0;
        int byteread = 0;
        File oldfile = file;
        if (oldfile.exists()) { // 文件存在时
            try (InputStream inStream = new FileInputStream(oldfile)) { // 读入原文件
                byte[] buffer = new byte[1024];
                int length;
                while ((byteread = inStream.read(buffer)) != -1) {
                    bytesum += byteread; // 字节数 文件大小
                    out.write(buffer, 0, byteread);
                }
                inStream.close();
                out.close();
                return true;
            } catch (IOException e) {
                log.error(e.getMessage());
                return false;
            }
        } else {
            return false;
        }

    }

    /**
     * 递归删除文件目录
     *
     * @param dir
     * @return boolean
     * @author hufx
     * @date 2018年2月9日下午4:33:19
     */
    public static boolean fileDel(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            if (children == null || children.length < 1) {
                return dir.delete();
            }
            // 递归删除目录中的子目录下
            for (int i = 0; i < children.length; i++) {
                boolean success = fileDel(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空，可以删除
        return dir.delete();
    }

    /**
     * MultipartFile 转换成File
     *
     * @param multfile 原文件类型
     * @return File
     * @throws IOException
     */
    public static File multipartToFile(String path, MultipartFile multfile) throws IOException {
        String suffix = multfile.getOriginalFilename().substring(multfile.getOriginalFilename().lastIndexOf("."));
        File dest = new File(path + "/" + UUID.randomUUID().toString().replaceAll("-", "") + suffix);
        if (!dest.exists()) {
            dest.getParentFile().mkdirs();
            if (!dest.createNewFile()) {
                return null;
            }
        }

        multfile.transferTo(dest);
        log.info("生成文件 --> " + dest.getAbsolutePath());
        return dest;
    }

    /**
     * 递归删除
     */
    public static boolean recursion(File r) {
        try {
            log.info("文件源路径 --> " + r.getAbsolutePath());
            if (r.isDirectory()) {
                for (File rc : r.listFiles()) {
                    recursion(rc);
                }
            } else {
                log.info("删除文件 --> " + r.getAbsolutePath());
                return r.delete();
            }
        } catch (Exception e) {
            System.out.println("异常信息 --> " + e);
        }
        return r.delete();
    }

    /**
     * 使用dos命令强力删除目录 强力删除文件夹,里面就算有子文件夹,隐藏的,只读的,都能够全部删除掉. directory 需要删除的目录 return
     * 如果目录不存在,则返回"目录不存在";删除成功,返回ok;删除失败 ,返回失败原因
     */
    public static String forceDeleteDirectory(String directory) {
        File tagFile = new File(directory);
        if (tagFile.exists()) {
            try {
                String cmd = "cmd /c rd " + directory + " /s/q";
                Runtime rt = Runtime.getRuntime(); // 获取运行时系统
                rt.exec(cmd); // 执行命令
            } catch (Throwable t) {
                return t.getMessage();
            }
            return "ok";
        } else {
            return "目录不存在";
        }
    }

    /**
     * 功能描述:是否是英文
     *
     * @param:
     * @return:
     * @auther: yfl
     * @date: 2018/10/10 15:46
     */
    public static boolean isEnglish(String charaString) {

        return charaString.matches("^[a-zA-Z]*");

    }

    /**
     * 功能描述: 是否是中文
     *
     * @param:
     * @return:
     * @auther: yfl
     * @date: 2018/10/10 15:46
     */
    public static boolean isChinese(String str) {

        String regEx = "[\\u4e00-\\u9fa5]+";

        Pattern p = Pattern.compile(regEx);

        Matcher m = p.matcher(str);

        if (m.find())

            return true;

        else

            return false;

    }


    /**
     * java对象转json时Date日期的处理配置类 <br/>
     * 此类用于处理以下问题：<br/>
     * 将java对象使用JSONObject.fromObject(Object)进行转换并且使用JSONObject.toString()返回字符串时,<br/>
     * 会默认将java.util.Date日期转换成下列结果： <br/>
     * "birthday": { "date": 3, "day": 4, "hours": 9, "minutes": 5, "month": 11,
     * "seconds": 1, "time": 1449104701018, "timezoneOffset": -480, "year": 115 },
     * <br/>
     * 为了方便JSON数据的直接使用，因此需要进行配置转换
     *
     * @author hufx
     * @version 1.0
     * @date 2018年2月10日下午3:01:55
     */
    private static class JsonDateValueProcessor implements JsonValueProcessor {
        // 日期格式化规则
        private String pattern = null;

        /**
         * 使用默认构造方法处理时，将返回原来java.util.Date 的toString()方法结果
         */
        public JsonDateValueProcessor() {

        }

        /**
         * 使用此构造方法处理时，将根据指定的格式返回java.util.Date format后的字符串结果
         *
         * @param pattern
         */
        public JsonDateValueProcessor(String pattern) {
            this.pattern = pattern;
        }

        public Object processArrayValue(Object value, JsonConfig config) {
            return process(value);
        }

        public Object processObjectValue(String key, Object value, JsonConfig config) {
            return process(value);
        }

        private Object process(Object value) {
            if (value instanceof Date) {
                // 如果日期格式化规则不可用,则返回java.util.Date().toString()
                if (StringUtils.isBlank(pattern)) {
                    if (ObjectUtil.isNull(value)) {
                        return "";
                    } else {
                        return value.toString();
                    }
                } else {// 如果日期格式化规则可用，则返回格式化后的日期结果
                    SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                    return sdf.format(value);
                }
            }
            if (ObjectUtil.isNull(value)) {
                return "";
            } else {
                return value.toString();
            }
        }


    }

    /**
     * 通过时间秒毫秒数判断两个时间的间隔
     *
     * @param date1
     * @param date2
     * @return
     */
    public static int differentDaysByMillisecond(Date date1, Date date2) {
        int days = (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24));
        return days;
    }

    public static String getStringDate(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return simpleDateFormat.format(date);
    }

    public static String getStrDate(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        return simpleDateFormat.format(date);
    }

    public static String getYear(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy");
        return simpleDateFormat.format(date);
    }

    public static String getHour(Date date) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
        return simpleDateFormat.format(date);
    }

    /**
     * 7    * 获取现在时间
     * 8    *
     * 9    * @return 返回时间类型 yyyy-MM-dd HH:mm:ss
     * 10
     */
    public static Date getDate(String strDate) throws Exception {
        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = format.parse(strDate);
        return date;
    }

    /**
     * @param date
     * @Description 截取字符串date
     * @Return java.lang.Long
     * @Author wh
     * @Date 2020/7/24 14:59
     **/
    public static Long changeStr(String date) {
        String newDate = date.substring(6, date.length() - 7);
        long time = Long.parseLong(newDate);
        return time;
    }

    /**
     * @param start
     * @param end
     * @param date
     * @Description 判断出井时间是否在某时间段内
     * @Return boolean
     * @Author wh
     * @Date 2020/7/31 17:36
     **/
    public static boolean compTime(String start, String end, Date date) {
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
            String strDate = simpleDateFormat.format(date);
            String[] strDateArray = strDate.split(":");
            int total = Integer.valueOf(strDateArray[0]) * 3600 + Integer.valueOf(strDateArray[1]) * 60 + Integer.valueOf(strDateArray[2]);
            String[] array1 = start.split(":");
            int total1 = Integer.valueOf(array1[0]) * 3600 + Integer.valueOf(array1[1]) * 60 + Integer.valueOf(array1[2]);
            String[] array2 = end.split(":");
            int total2 = Integer.valueOf(array2[0]) * 3600 + Integer.valueOf(array2[1]) * 60 + Integer.valueOf(array2[2]);
            if (total1 <= total && total <= total2) {
                return true;
            }
        } catch (NumberFormatException e) {
            log.error("时间比较 失败", e);
        }
        return false;
    }

    //时间向后推一天
    public static Date getNewDate(Date date, int i) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(calendar.DATE, i);//把日期往后增加一天.整数往后推,负数往前移动
        date = calendar.getTime();   //这个时间就是日期往后推一天的结果
        return date;
    }

    //判断日期是否在区间
    public static boolean yearMonthBetween(String nowDate, String startDate, String endDate) throws Exception {

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

        Date now = format.parse(nowDate);
        Date start = format.parse(startDate);
        Date end = format.parse(endDate);

        long nowTime = now.getTime();
        long startTime = start.getTime();
        long endTime = end.getTime();

        return nowTime >= startTime && nowTime <= endTime;
    }

    /**
     * 本地文件（图片、excel等）转换成Base64字符串
     *
     * @param imgPath
     */
    public static String convertFileToBase64(String imgPath) {
        byte[] data = null;
        // 读取图片字节数组
        try {
            InputStream in = new FileInputStream(imgPath);
            System.out.println("文件大小（字节）=" + in.available());
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            log.error("转换成Base64字符串 失败", e);
        }
        // 对字节数组进行Base64编码，得到Base64编码的字符串
        Base64Encoder encoder = new Base64Encoder();
        return encoder.encode(data);
    }

    /**
     * 获取当天开始时间
     *
     * @param date
     * @return
     */
    public static Date getStartTime(Date date) {
        Calendar dateStart = Calendar.getInstance();
        dateStart.setTime(date);
        dateStart.set(Calendar.HOUR_OF_DAY, 0);
        dateStart.set(Calendar.MINUTE, 0);
        dateStart.set(Calendar.SECOND, 0);
        return dateStart.getTime();
    }

    /**
     * 获取当天结束时间
     *
     * @param date
     * @return
     */
    public static Date getEndTime(Date date) {
        Calendar dateEnd = Calendar.getInstance();
        dateEnd.setTime(date);
        dateEnd.set(Calendar.HOUR_OF_DAY, 23);
        dateEnd.set(Calendar.MINUTE, 59);
        dateEnd.set(Calendar.SECOND, 59);
        return dateEnd.getTime();
    }

    /**
     * @Description 判断是否为周天
     * @Param [date]
     * @Return boolean
     * @Author wh
     * @Date 2021/3/2
     **/
    public static boolean isMonday(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int week = calendar.get(Calendar.DAY_OF_WEEK);
        if (week == 1) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * @Description 判断两个集合是否完全相同
     * @Author wh
     * @Param [list1, list2]
     * @Return boolean
     * @Date 2021/7/22
     **/
    public static boolean checkDifferent(List<Integer> list1, List<Integer> list2) {
        list1.sort(Integer::compareTo);
        list2.sort(Integer::compareTo);
        return list1.toString().equals(list2.toString());
    }

    /**
     * 身份证正确性验证
     *
     * @param IDNumber
     * @return
     */
    public static boolean isIDNumber(String IDNumber) {
        // 定义判别用户身份证号的正则表达式（15位或者18位，最后一位可以为字母）
        String regularExpression = "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|" +
                "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";
        //假设18位身份证号码:41000119910101123X  410001 19910101 123X
        //^开头
        //[1-9] 第一位1-9中的一个      4
        //\\d{5} 五位数字           10001（前六位省市县地区）
        //(18|19|20)                19（现阶段可能取值范围18xx-20xx年）
        //\\d{2}                    91（年份）
        //((0[1-9])|(10|11|12))     01（月份）
        //(([0-2][1-9])|10|20|30|31)01（日期）
        //\\d{3} 三位数字            123（第十七位奇数代表男，偶数代表女）
        //[0-9Xx] 0123456789Xx其中的一个 X（第十八位为校验值）
        //$结尾

        //假设15位身份证号码:410001910101123  410001 910101 123
        //^开头
        //[1-9] 第一位1-9中的一个      4
        //\\d{5} 五位数字           10001（前六位省市县地区）
        //\\d{2}                    91（年份）
        //((0[1-9])|(10|11|12))     01（月份）
        //(([0-2][1-9])|10|20|30|31)01（日期）
        //\\d{3} 三位数字            123（第十五位奇数代表男，偶数代表女），15位身份证不含X
        //$结尾


        boolean matches = IDNumber.matches(regularExpression);

        //判断第18位校验值
        if (matches) {

            if (IDNumber.length() == 18) {
                try {
                    char[] charArray = IDNumber.toCharArray();
                    //前十七位加权因子
                    int[] idCardWi = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
                    //这是除以11后，可能产生的11位余数对应的验证码
                    String[] idCardY = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
                    int sum = 0;
                    for (int i = 0; i < idCardWi.length; i++) {
                        int current = Integer.parseInt(String.valueOf(charArray[i]));
                        int count = current * idCardWi[i];
                        sum += count;
                    }
                    char idCardLast = charArray[17];
                    int idCardMod = sum % 11;
                    if (idCardY[idCardMod].toUpperCase().equals(String.valueOf(idCardLast).toUpperCase())) {
                        return true;
                    } else {
                        return false;
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
            }

        }
        return matches;
    }


    /**
     * 从身份证中获取出生年月：yyyy-mm-dd
     *
     * @param idNumber
     * @return
     */
    public static String getBirthdayFromIDNumber(String idNumber) {
        if (StringUtils.isEmpty(idNumber)) {
            return null;
        }
        String birthday = null;
        if (idNumber.length() == 18) {
            birthday = String.format("%s-%s-%s", idNumber.substring(6, 10), idNumber.substring(10, 12),
                    idNumber.substring(12, 14));
        } else if (idNumber.length() == 15) {
            birthday = String.format("%s-%s-%s", "19" + idNumber.substring(6, 8), idNumber.substring(8, 10),
                    idNumber.substring(10, 12));
        }
        return birthday;
    }

    /**
     * 从身份证中获取性别：1：男，0：女
     *
     * @param idNumber
     * @return
     */
    public static Integer getSexFromIDNumber(String idNumber) {
        if (StringUtils.isEmpty(idNumber)) {
            return null;
        }
        String sexNumber = null;
        if (idNumber.length() == 18) {
            sexNumber = idNumber.substring(16, 17);
        } else if (idNumber.length() == 15) {
            sexNumber = idNumber.substring(14, 15);
        }
        if (StringUtils.isEmpty(sexNumber)) {
            return null;
        }
        return Integer.parseInt(sexNumber) & 1;
    }

}
